#More recent samples have higher weight. Better step response than SMA.

FUNCTION_BLOCK FB_WMA
VAR_INPUT
    xEnable     : BOOL;
    rInput      : REAL;
    iWindowSize : INT := 8;    // Max 16
END_VAR
VAR_OUTPUT
    rOutput : REAL;
END_VAR
VAR
    arBuffer    : ARRAY[0..15] OF REAL;
    iIndex      : INT := 0;
    iCount      : INT := 0;
    iWin        : INT;
    rWeightSum  : REAL;
    rValSum     : REAL;
    i           : INT;
    iPos        : INT;
    rWeight     : REAL;
END_VAR

IF NOT xEnable THEN
    iIndex := 0; iCount := 0; rOutput := rInput;
    RETURN;
END_IF;

iWin := MIN(MAX(iWindowSize, 1), 16);

// Store newest sample
arBuffer[iIndex] := rInput;
iIndex := (iIndex + 1) MOD iWin;
IF iCount < iWin THEN iCount := iCount + 1; END_IF;

// Calculate weighted sum (weight = position, newest = highest)
rWeightSum := 0.0;
rValSum    := 0.0;
FOR i := 0 TO iCount - 1 DO
    // Most recent sample is at (iIndex - 1), going back
    iPos    := (iIndex - 1 - i + iWin * 2) MOD iWin;
    rWeight := INT_TO_REAL(iCount - i);     // Newest gets weight=iCount, oldest=1
    rValSum    := rValSum    + arBuffer[iPos] * rWeight;
    rWeightSum := rWeightSum + rWeight;
END_FOR;

IF rWeightSum > 0.0 THEN
    rOutput := rValSum / rWeightSum;
END_IF;